unit BD_LabJack;

interface
uses
LJUDDelphi, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
VCL.Dialogs, BD_UUT;

(******************************************************************************
LabJack Constants
*******************************************************************************)
const
//DIO "Channels" referenced as bit position from F0..C4
PF0 = 0;
PF1 = 1;
PF2 = 10;
PF3 = 3;
PF4 = 4;
PF5 = 5;
PF6 = 6;
PF7 = 7;
PE0 = 8;       //PE0 used as SCI TX
PE1 = 9;       //PE1 uses as SCI RX
PE2 = 10;
PVENT = 10;
PE3 = 11;
PHIGHLOW = 11;
PE4 = 12;
PTIP = 12; //TEST IN PROGRESS light
PE5 = 13;
PPASS = 13;  //PASS lamp
PE6 = 14;
PFAIL = 14;  //FAIL lamp
PE7 = 15;
PSENS = 15;  //SENSOR CONTACT lamp
PC0 = 16;
PFASTEST = 16;  //FAS-TEST Solenoid
PC1 = 17;
PSEAL = 17;     //SEAL Solenoid
PC2 = 18;
PC3 = 19;
//Analog Input Channels
ACH_BATT = 0;   //Battery voltage

(**********CUSTOM CLASSES AND ENUMERATED TYPES FOR Lab Jack***********)

(******************************************************************************
  TSharedmem: This class contains public fields that will be shared by the main
              thread and the thread that is communicating between the LabJack
              UART and the UUT.
              It is CRITICAL that the thread use the 'Synchronize' method to
              modify this data to prevent conflicts with the main thread.
*******************************************************************************)
type TSharedMem = class
  public
    fRxDat: array[1..32] of byte;
    fRxCnt: Integer;
    fStatusMsg: string;
end;

(*******************************************************************************
  TSystemLabJacks is a record type that contains information about the Lab Jacks
  currently attached to the system.
********************************************************************************)
type TSystemLabJack = record
  Sn, Id: longint;
  Addr: Double;
end;

//Must declare an array type to allow TSystemLabJack to be passed as an array
TSysLJArray = array of TSystemLabJack;
(******************************************************************************
TLabJack Class Description
*****************************************************************************)
type TLabJack = class
    //private member data
    //private member methods

  public
    //public member data
    ErrorCode: Integer;
    Hnd: LJ_HANDLE;
    Name: pAnsiChar;
    IOType: LongInt;
    Channel: LongInt;
    err: array[0..254] of char;
    errNum: Integer;
    errStr: string;
    errIteration: Integer;
    localID: Double;      //ID of LabJack on bus (we can set this)
    hwVersion: Double;    //hardware version of LabJack
    serialNum: Double;     //LabJack SN
    fwVersion: Double;     //Firmware version
    doStream: Boolean;     //flag to tell stream process to stop
    U3Backlog: Double;
    drvBacklog: Double;
    //LJ Comport members
    txData: array of byte;
    RxD: TByteArr;
    var RxData: array of byte;   //Array to hold RX data in the LJ buffer from the UUT. 32 is max buffer size.
    var RxCnt: Double;      //number of bytes read from the UUT
    iRxCnt: Integer;        //integer conversion of RxCnt.
    RxRespTime: Integer;     //The amount of time a typical response is expected in mS
    RxRespTries: Integer;     //Max Number of times RX buffer can be read for a given command/response attepmt
    RxRespCnt: Integer;      //count and track the number of retires.
    procedure InitLabJack;
    procedure ErrorHandler(func: string);
    procedure PutBit(bitPos: Integer; Val: Integer);
    procedure CloseLabJack;
    procedure GetAnalogInput(Ch: Integer; var Val: Double);
    procedure WriteUART(var TxData: array of byte);
    function ReadUART2(var buf: array of byte): Integer;
    procedure ReadUART;
    procedure FlushUART;  //Flush the UART, discarding any data in the buffer

end;

procedure FindAllLabJacks(var LJs: TSysLJArray);

implementation
uses BDPgmCalMTMain;

(******************************************************************************
  FindAllLabJacks: locates labjacks currently connected via USB to the system,
                   and returns their addresses.
*******************************************************************************)
procedure FindAllLabJacks(var LJs: TSysLJArray);
var
  Sn, Id: array[0..127] of longint;
  Addr: array[0..127] of Double;
  Total, i: Integer;
begin
  if ListAll(LJ_dtU3, LJ_ctUSB, Total, @Sn, @Id, @Addr) <> LJE_NOERROR then
    ShowMessage('Error occured while trying locate attached Lab Jack devices.')
    else
      begin
        SetLength(LJs, Total);
        for i := Low(Sn) to Total-1 do
          begin
            LJs[i].Sn := Sn[i];
            LJs[i].Id := Id[i];
            LJs[i].Addr := Addr[i];
          end;
      end;
end;


(******************************************************************************
  InitLabJack: locates labjack, obtains information and saves to the labjack
                object for use by other functions.
*******************************************************************************)
procedure TLabJack.InitLabJack;
begin
  //initialize values
  Hnd := 0;
  IOType := 0;
  Channel := 0;
  ErrorCode :=  LJE_NOERROR;
  //try to find a labjack.
  try
    { Open first found LabJack. }
    ErrorCode := OpenLabJack(LJ_dtU3, LJ_ctUSB, '1', 0, Hnd);
    ErrorHandler('LJM_Open');
    { Call LJM_eReadName to read the serial number from the LabJack. }
    if ErrorCode = LJE_NOERROR then
     begin
       //Get the labjack information
       ErrorCode := eGet(Hnd, LJ_ioGET_CONFIG, LJ_chLOCALID, localID, 0);    //get the local id
       ErrorHandler('eGet');
       ErrorCode :=eGet(Hnd, LJ_ioGET_CONFIG, LJ_chHARDWARE_VERSION, hwVersion, 0);    //get the Hardware Version
       ErrorHandler('eGet');
       ErrorCode :=eGet(Hnd, LJ_ioGET_CONFIG, LJ_chSERIAL_NUMBER, &serialNum, 0);    //get the Serial Number
       ErrorHandler('eGet');
       ErrorCode :=eGet(Hnd, LJ_ioGET_CONFIG, LJ_chFIRMWARE_VERSION, &fwVersion, 0);    //get the Firmware Version
       ErrorHandler('eGet');
       frmMain.sbStatus.Panels[0].Text := 'LabJack S/N '+FloatToStr(serialNum);
       //Set the T/C offset to E0  (offset of 8)
       ErrorCode := ePut (Hnd, LJ_ioPUT_CONFIG, LJ_chTIMER_COUNTER_PIN_OFFSET, 8, 0);
       ErrorHandler('ePut: Set T/C Offset.');
        //Now set up the UART: set baud rate  & enable
       ErrorCode := ePut(Hnd,LJ_ioPUT_CONFIG, LJ_chASYNCH_BAUDFACTOR, 64286, 0);        //baud rate to 19,200
       ErrorHandler('ePut: configuring baud rate.');
       ErrorCode := ePut(Hnd,LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_ENABLE, 1, 0);       //Uart Enabled async comms
       ErrorHandler('ePut: enabling ASYNCH comms. ');
    end;
  except
     ShowMessage('Error encountered while attempting to open LabJack.');
  end;
end;

procedure TLabJack.ErrorHandler(func: string);
begin
  if ErrorCode <> LJE_NOERROR then
    ShowMessage('LabJack error occured. Error code: '+ func + ': '+IntToStr(ErrorCode));
end;

(********************************************************************************
  PutBit: This method writes the desired val (0 or 1) to the specified bit position.
*******************************************************************************)
procedure TLabJack.PutBit(bitPos: Integer; Val: Integer);
begin
  ErrorCode := eDO(Hnd, bitPos, Val);
  ErrorHandler('eDO');
end;
(******************************************************************************
  CloseLabJack: Close the LabJack gracefully.
*******************************************************************************)
procedure TLabJack.CloseLabJack;
begin
  Close();
end;

(******************************************************************************
  GetAnalogInput: Read the analog value from the channel specified.
*******************************************************************************)
procedure TLabJack.GetAnalogInput(Ch: Integer; var Val: Double);
begin
  ErrorCode := eGet(Hnd, LJ_ioGET_AIN, Ch, Val, 0);
  ErrorHandler('eGet');
end;

(******************************************************************************
  WriteUART: Write data to the serial device connected to the LJ via ASYNCH comm
*******************************************************************************)
procedure TLabJack.WriteUART(var TxData: array of byte);
var
  txCnt: Double;
begin
  txCnt := Length(TxData);
  ErrorCode := eGet(Hnd, LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_TX, txCnt, @TxData);
  ErrorHandler('eGet: WriteUART');
end;

(******************************************************************************
  ReadUART: Read data from the serial device connected to the LJ via ASYNCH comm
*******************************************************************************)
procedure TLabJack.ReadUART;
begin
   SetLength(RxData,32);
   ErrorCode := eGet(Hnd, LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_RX, RxCnt, RxData);
   ErrorHandler('eGet: ReadUART');
   LJ.iRxCnt := Round(LJ.RxCnt);   //Will use integer version for all external operations.
end;

function TLabJack.ReadUART2(var buf: array of byte): Integer;
var
  cnt: double;
begin
   ErrorCode := eGet(Hnd, LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_RX, cnt, @buf);
   ErrorHandler('eGet: ReadUART');
   Result := Round(cnt);   //Will use integer version for all external operations.
end;

(******************************************************************************
  FlushUART: Flush the UART, discarding any data in the buffer.
*******************************************************************************)
procedure TLabJack.FlushUART;
var
  numBytes: Double;
begin
  ErrorCode := eGet(Hnd, LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_FLUSH, numBytes, 0);
  ErrorHandler('eGet: FlushUART');
end;


end.
